package metricstore

import (
	"fmt"

	"gitee.com/shipnet/flogo-common/metric"
	"github.com/project-flogo/core/activity"
	"github.com/project-flogo/core/data/metadata"
)

// Activity activity
type Activity struct {
	store metric.Store
}

func init() {
	_ = activity.Register(&Activity{}, New)
}

// New create new activity
func New(ctx activity.InitContext) (activity.Activity, error) {
	settings := Settings{}
	err := metadata.MapToStruct(ctx.Settings(), &settings, true)
	if err != nil {
		return nil, err
	}
	rs := metric.Settings{
		Addr:      settings.Addr,
		DB:        settings.DB,
		Password:  settings.Password,
		KeyPrefix: settings.KeyPrefix,
	}
	store, err := metric.New(rs)
	if err != nil {
		return nil, err
	}
	act := Activity{
		store: store,
	}
	return &act, nil
}

var md = activity.ToMetadata(&Input{}, &Output{}, &Settings{})

// Metadata returns metadata
func (a *Activity) Metadata() *activity.Metadata {
	return md
}

// Eval evaluate activity
func (a *Activity) Eval(ctx activity.Context) (bool, error) {
	input := Input{}
	err := ctx.GetInputObject(&input)
	if err != nil {
		return true, err
	}

	switch input.Op {
	case "GET":
		{
			return a.evalGet(ctx, &input)
		}
	case "SET":
		{
			return a.evalSet(ctx, &input)
		}
	default:
		{
			return true, fmt.Errorf("invalid op: %s", input.Op)
		}
	}
}

func (a *Activity) evalGet(ctx activity.Context, input *Input) (bool, error) {
	id := input.MetricID
	v, err := a.store.Get(id)
	output := Output{
		Data: *v,
		Err:  errToString(err),
	}
	err = ctx.SetOutputObject(&output)
	return true, err
}

func (a *Activity) evalSet(ctx activity.Context, input *Input) (bool, error) {
	err := a.store.Set(input.Data)
	output := Output{
		Data: input.Data,
		Err:  errToString(err),
	}
	err = ctx.SetOutputObject(&output)
	return true, err
}

func errToString(err error) string {
	if err == nil {
		return ""
	}
	return err.Error()
}
